Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Communication: Add emoji support to messages #9595

Merged
merged 10 commits into from
Oct 27, 2024

Conversation

asliayk
Copy link
Contributor

@asliayk asliayk commented Oct 25, 2024

Checklist

General

Client

  • I strictly followed the client coding and design guidelines.
  • Following the theming guidelines, I specified colors only in the theming variable files and checked that the changes look consistent in both the light and the dark theme.
  • I added multiple integration tests (Jest) related to the features (with a high test coverage), while following the test guidelines.
  • I documented the TypeScript code using JSDoc style.
  • I added multiple screenshots/screencasts of my UI changes.
  • I translated all newly inserted strings into English and German.

Motivation and Context

Users currently cannot select and send emojis, limiting their expressive options in messages.

Description

  • Added an emoji button that opens an emoji picker, allowing users to select and send emojis in their messages.
  • Emojis now automatically convert as user types —for instance, ":)" changes to 🙂.

Steps for Testing

Prerequisites:

  • 1 Instructor/Student
  • 1 Course with Communication enabled
  1. Log in to Artemis
  2. Navigate to Communication section of a course
  3. Open a random channel to send a message
  4. Notice the emoji button on the input area, click on it to open the emoji picker
  5. Select an emoji and send it to see it on the conversation.
  6. Try automatic conversion: type something such as ":)", ":/", ":D", or ":+1: and see their emoji versions on the input area.

Testserver States

Note

These badges show the state of the test servers.
Green = Currently available, Red = Currently locked
Click on the badges to get to the test servers.







Review Progress

Code Review

  • Code Review 1
  • Code Review 2

Manual Tests

  • Test 1
  • Test 2

Test Coverage

Class/File Line Coverage Confirmation (assert/expect)
markdown-editor-monaco.component.ts 95.36% ✅ ❌
posting-markdown-editor.component.ts 100%
emoji.action.ts 75.6% ✅ ❌
monaco-editor.component.ts 94.55% ✅ ❌

Screenshots

image
image

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced emoji insertion functionality in the markdown editor, allowing users to enhance their text with emojis.
    • Updated button actions for improved handling of user interactions.
    • Enhanced text handling capabilities to automatically convert emoticons to emojis.
    • Added support for emoji localization in both English and German language files.
  • Bug Fixes

    • Improved emoji picker display and interaction handling within the editor.
  • Tests

    • Expanded test coverage for the new emoji functionality, ensuring proper integration and behavior within the editor.

@asliayk asliayk added client Pull requests that update TypeScript code. (Added Automatically!) component:Communication labels Oct 25, 2024
@asliayk asliayk self-assigned this Oct 25, 2024
@asliayk asliayk requested a review from a team as a code owner October 25, 2024 17:37
@github-actions github-actions bot added the tests label Oct 25, 2024
Copy link

coderabbitai bot commented Oct 25, 2024

Walkthrough

The changes in this pull request primarily enhance the functionality of the Markdown editor components by introducing emoji support. Key modifications include updating the click event handler in the markdown-editor-monaco.component.html, adding a new handleActionClick method in the MarkdownEditorMonacoComponent, and creating an EmojiAction class to manage emoji interactions. Additionally, the PostingMarkdownEditorComponent has been updated to include the new emoji features, and corresponding localization entries have been added to support emoji in both German and English. Tests have also been updated to reflect these changes.

Changes

File Change Summary
src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.html Updated click event in simpleActionButton from action.executeInCurrentEditor() to handleActionClick($event, action).
src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.ts Added import for EmojiAction and new method handleActionClick(event: MouseEvent, action: TextEditorAction).
src/main/webapp/app/shared/metis/posting-markdown-editor/posting-markdown-editor.component.ts Updated constructor to include ViewContainerRef, Overlay, and OverlayPositionBuilder; added EmojiAction to defaultActions.
src/main/webapp/app/shared/monaco-editor/model/actions/emoji.action.ts Introduced EmojiAction class with methods for handling emoji picker functionality.
src/main/webapp/i18n/de/multipleChoiceQuestion.json Added "emoji": "Emoji" key to the editor section.
src/main/webapp/i18n/en/multipleChoiceQuestion.json Added "emoji": "Emoji" key to the editor object.
src/test/javascript/spec/component/shared/metis/postings-markdown-editor/postings-markdown-editor.component.spec.ts Added imports for EmojiAction, Overlay, and TextEditor; updated tests for emoji handling.
src/test/javascript/spec/component/shared/monaco-editor/monaco-editor.component.spec.ts Added tests for convertTextToEmoji and isConvertedToEmoji methods in MonacoEditorComponent.
package.json Added dependencies: "@types/emoji-js": "^3.5.2" and "emoji-js": "^3.8.0".
src/main/webapp/app/shared/monaco-editor/monaco-editor.component.ts Introduced emojiConvertor and methods for emoji conversion in MonacoEditorComponent.

Possibly related PRs

Suggested labels

user interface, ready to merge

Suggested reviewers

  • florian-glombik
  • az108
  • JohannesStoehr
  • pzdr7
  • Malekos74

📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 2cfbd87 and d197cc4.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • package.json (2 hunks)
  • src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.html (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • package.json
  • src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.html

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @coderabbitai title anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🧹 Outside diff range and nitpick comments (5)
src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.html (1)

Based on the analysis of the code and implementation, I can now provide a final response regarding the emoji picker accessibility:

Emoji picker accessibility needs improvement

The current implementation has some accessibility gaps that should be addressed:

  1. The emoji picker component lacks proper ARIA attributes for keyboard navigation and screen reader support
  2. The emoji-mart component being used (@ctrl/ngx-emoji-mart v9.2.0) needs to be wrapped with proper accessibility attributes
  3. The picker positioning is handled programmatically but lacks keyboard focus management

Recommended improvements:

  • Add role="dialog" and aria-label to the emoji picker overlay
  • Implement keyboard navigation support (Esc to close, arrow keys for navigation)
  • Add proper focus management when the picker opens and closes
  • Include screen reader announcements for picker state changes
🔗 Analysis chain

Line range hint 232-238: Verify emoji picker positioning and accessibility.

The click handler change supports emoji functionality by passing the event object for positioning. However, we should ensure:

  1. The emoji picker is properly positioned relative to the button
  2. The picker is accessible via keyboard navigation

Let's verify the accessibility implementation:


Based on the search results, I can see that there are ARIA attributes being used throughout the codebase, but I need to specifically check the emoji picker implementation. Let me search for emoji-related components and their accessibility attributes.


Let me check the emoji picker component implementation specifically to verify its accessibility features.


Let me check the underlying emoji-mart component's accessibility features since it's being used as the base component.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if there are appropriate ARIA attributes for the emoji picker
rg -g '*.html' -g '*.ts' 'aria-' -A 3 -B 3

Length of output: 179891


Script:

#!/bin/bash
# Search for emoji picker related files and components
rg -g '*.{html,ts}' -i 'emoji.*picker|picker.*emoji' -A 3 -B 3

Length of output: 25740


Script:

#!/bin/bash
# Check the emoji picker component template and implementation
cat src/main/webapp/app/shared/metis/emoji/emoji-picker.component.html

Length of output: 623


Script:

#!/bin/bash
# Check package.json for emoji-mart version and check node_modules for accessibility features
cat package.json | grep -A 5 -B 5 "emoji-mart"

Length of output: 584

src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.ts (1)

Line range hint 152-164: Add EmojiAction to defaultActions array.

The EmojiAction is imported but not included in the defaultActions array. To enable emoji support as intended in the PR objectives, the EmojiAction should be added to the defaultActions.

Add EmojiAction to the defaultActions array:

     @Input()
     defaultActions: TextEditorAction[] = [
         new BoldAction(),
         new ItalicAction(),
         new UnderlineAction(),
         new QuoteAction(),
         new CodeAction(),
         new CodeBlockAction('java'),
         new UrlAction(),
         new AttachmentAction(),
         new OrderedListAction(),
         new UnorderedListAction(),
+        new EmojiAction(),
     ];
src/main/webapp/app/shared/monaco-editor/model/actions/emoji.action.ts (3)

71-72: Avoid using inline styles; prefer CSS classes for styling.

Setting styles directly using style.transform can make the code harder to maintain. Instead, define a CSS class with the desired styles and apply it to the element to improve readability and maintainability.


106-108: Inline simple helper method to reduce complexity.

The insertTextAtPosition method is a simple wrapper around replaceTextAtRange. If there's no plan to extend its functionality, consider inlining this method to simplify the code.


24-24: Remove unnecessary 'undefined' parameter in constructor.

The fourth parameter in the superclass constructor is undefined, which is unnecessary. Removing it simplifies the code without affecting functionality.

Apply this diff to remove the redundant parameter:

-            super(EmojiAction.ID, 'artemisApp.multipleChoiceQuestion.editor.emoji', faSmile, undefined);
+            super(EmojiAction.ID, 'artemisApp.multipleChoiceQuestion.editor.emoji', faSmile);
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 142c0f1 and 2cbc212.

📒 Files selected for processing (7)
  • src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.html (1 hunks)
  • src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.ts (2 hunks)
  • src/main/webapp/app/shared/metis/posting-markdown-editor/posting-markdown-editor.component.ts (4 hunks)
  • src/main/webapp/app/shared/monaco-editor/model/actions/emoji.action.ts (1 hunks)
  • src/main/webapp/i18n/de/multipleChoiceQuestion.json (1 hunks)
  • src/main/webapp/i18n/en/multipleChoiceQuestion.json (1 hunks)
  • src/test/javascript/spec/component/shared/metis/postings-markdown-editor/postings-markdown-editor.component.spec.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.html (1)

Pattern src/main/webapp/**/*.html: @if and @for are new and valid Angular syntax replacing *ngIf and *ngFor. They should always be used over the old style.

src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.ts (1)

Pattern src/main/webapp/**/*.ts: angular_style:https://angular.io/guide/styleguide;methods_in_html:false;lazy_loading:true;code_reuse:true;tests:meaningful;types:PascalCase;enums:PascalCase;funcs:camelCase;props:camelCase;no_priv_prefix:true;strings:single_quotes;localize:true;btns:functionality;links:navigation;icons_text:newline;labels:associate;code_style:arrow_funcs,curly_braces,open_braces_same_line,indent_4;memory_leak_prevention:true;routes:naming_schema;chart_framework:ngx-charts;responsive_layout:true

src/main/webapp/app/shared/metis/posting-markdown-editor/posting-markdown-editor.component.ts (1)

Pattern src/main/webapp/**/*.ts: angular_style:https://angular.io/guide/styleguide;methods_in_html:false;lazy_loading:true;code_reuse:true;tests:meaningful;types:PascalCase;enums:PascalCase;funcs:camelCase;props:camelCase;no_priv_prefix:true;strings:single_quotes;localize:true;btns:functionality;links:navigation;icons_text:newline;labels:associate;code_style:arrow_funcs,curly_braces,open_braces_same_line,indent_4;memory_leak_prevention:true;routes:naming_schema;chart_framework:ngx-charts;responsive_layout:true

src/main/webapp/app/shared/monaco-editor/model/actions/emoji.action.ts (1)

Pattern src/main/webapp/**/*.ts: angular_style:https://angular.io/guide/styleguide;methods_in_html:false;lazy_loading:true;code_reuse:true;tests:meaningful;types:PascalCase;enums:PascalCase;funcs:camelCase;props:camelCase;no_priv_prefix:true;strings:single_quotes;localize:true;btns:functionality;links:navigation;icons_text:newline;labels:associate;code_style:arrow_funcs,curly_braces,open_braces_same_line,indent_4;memory_leak_prevention:true;routes:naming_schema;chart_framework:ngx-charts;responsive_layout:true

src/main/webapp/i18n/de/multipleChoiceQuestion.json (1)

Pattern src/main/webapp/i18n/de/**/*.json: German language translations should be informal (dutzen) and should never be formal (sietzen). So the user should always be addressed with "du/dein" and never with "sie/ihr".

src/test/javascript/spec/component/shared/metis/postings-markdown-editor/postings-markdown-editor.component.spec.ts (1)

Pattern src/test/javascript/spec/**/*.ts: jest: true; mock: NgMocks; bad_practices: avoid_full_module_import; perf_improvements: mock_irrelevant_deps; service_testing: mock_http_for_logic; no_schema: avoid_NO_ERRORS_SCHEMA; expectation_specificity: true; solutions: {boolean: toBeTrue/False, reference: toBe, existence: toBeNull/NotNull, undefined: toBeUndefined, class_obj: toContainEntries/toEqual, spy_calls: {not_called: not.toHaveBeenCalled, once: toHaveBeenCalledOnce, with_value: toHaveBeenCalledWith|toHaveBeenCalledExactlyOnceWith}}

🔇 Additional comments (11)
src/main/webapp/i18n/de/multipleChoiceQuestion.json (1)

48-49: LGTM! The translations are correct and consistent.

The new German translations for the editor controls are accurate:

  • "Farbe" is the correct translation for "color"
  • "Emoji" is kept as is, which is correct as it's a commonly used loanword in German
src/main/webapp/app/shared/metis/posting-markdown-editor/posting-markdown-editor.component.ts (4)

15-15: LGTM: Import statements are well-organized.

The new imports are properly organized and necessary for implementing the emoji picker overlay functionality.

Also applies to: 34-35


Line range hint 71-88: Verify keyboard accessibility for emoji picker.

Since we're adding UI interaction elements, ensure that the emoji picker is keyboard accessible (can be opened with keyboard, navigated with arrow keys, and closed with Escape).

Run the following to check for keyboard event handlers:

#!/bin/bash
# Search for keyboard event handling in EmojiAction
ast-grep --pattern 'keydown' 
ast-grep --pattern 'keyup'
ast-grep --pattern 'keypress'

88-88: Consider grouping related actions together.

While the EmojiAction implementation looks correct, consider grouping it with other text enhancement actions (like UserMentionAction) for better toolbar organization.

Let's verify if there are any existing action grouping patterns:

#!/bin/bash
# Search for other components that might have action grouping patterns
rg -A 5 'defaultActions.*=' 'src/main/webapp'

71-73: Verify cleanup of overlay subscriptions.

While the constructor parameters are properly organized, ensure that any subscriptions created by the Overlay service are properly cleaned up to prevent memory leaks.

Consider implementing OnDestroy and cleaning up subscriptions:

-export class PostingMarkdownEditorComponent implements OnInit, ControlValueAccessor, AfterContentChecked, AfterViewInit {
+export class PostingMarkdownEditorComponent implements OnInit, ControlValueAccessor, AfterContentChecked, AfterViewInit, OnDestroy {
+    private readonly destroy$ = new Subject<void>();
+
+    ngOnDestroy(): void {
+        this.destroy$.next();
+        this.destroy$.complete();
+    }

Let's verify if there are any overlay subscriptions that need cleanup:

src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.html (2)

Line range hint 1-231: LGTM! Well-structured template with modern Angular syntax.

The template demonstrates excellent organization with clear separation of concerns between edit, visual, and preview modes. The consistent use of the new Angular control flow syntax (@if and @for) aligns with best practices.


Line range hint 1-238: LGTM! Excellent compliance with Angular coding guidelines.

The template consistently uses the new Angular control flow syntax (@if and @for) throughout, fully adhering to the coding guidelines.

src/main/webapp/app/shared/markdown-editor/monaco/markdown-editor-monaco.component.ts (1)

48-48: LGTM! Import statement follows Angular guidelines.

The import statement for EmojiAction is properly organized and consistent with other action imports.

src/main/webapp/app/shared/monaco-editor/model/actions/emoji.action.ts (2)

61-67: Review the necessity of setting 'width' to '0' in overlay configuration.

The overlay configuration sets width: '0', which might not be required and could lead to display issues with the emoji picker. Verify if this setting is necessary or if it can be omitted.


79-81: ⚠️ Potential issue

Ensure subscriptions are properly cleaned up to prevent memory leaks.

While disposing of the overlayRef helps manage resources, it's important to verify that all subscriptions, such as the one from backdropClick().subscribe, are also properly cleaned up to prevent memory leaks.

Run the following script to check for potentially unmanaged subscriptions:

✅ Verification successful

Let me analyze the code further to verify the subscription cleanup concern.


Let me analyze the code further to verify the subscription cleanup concern.


Let me try different shell scripts to analyze the code.


Let me analyze the code further to understand the subscription cleanup pattern.


Based on the code analysis, I can now provide a final response.

The subscription cleanup is properly handled

The subscription cleanup concern in emoji.action.ts is properly managed through multiple mechanisms:

  1. The EmojiAction class extends TextEditorAction which implements Disposable interface and provides cleanup through its dispose() method
  2. The overlayRef is properly cleaned up in the destroyEmojiPicker() method which is called:
    • When the emoji picker is closed via backdrop click
    • When a new emoji picker is opened
    • When an emoji is selected
  3. The subscription to emojiSelect is automatically cleaned up when the overlayRef is disposed, as it's tied to the component lifecycle through the Angular CDK's overlay system
  4. The subscription to backdropClick is also automatically cleaned up when the overlayRef is disposed

The implementation follows Angular CDK's overlay best practices where cleanup is handled through the disposal of the overlay reference, which internally manages all associated subscriptions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find subscriptions that may not be properly unsubscribed.

# Test: Search for '.subscribe(' in TypeScript files and check if they are managed appropriately.
rg '\.subscribe\(' --glob '**/*.ts'

Length of output: 413430


Script:

#!/bin/bash
# Search for ngOnDestroy implementations that unsubscribe/cleanup subscriptions
ast-grep --pattern 'ngOnDestroy() {
  $$$
}'

# Search for subscription cleanup patterns
rg -A 3 'takeUntil\(|unsubscribe\(\)|this\.destroy|this\.ngUnsubscribe'

Length of output: 230247


Script:

#!/bin/bash
# Search for the specific file and its subscription cleanup
rg -A 10 "emoji.action.ts" --glob "src/main/webapp/app/shared/monaco-editor/model/actions/emoji.action.ts"

# Search for the class implementation to see if it implements OnDestroy
ast-grep --pattern 'class $_ implements $$$OnDestroy$$$'

Length of output: 287


Script:

#!/bin/bash
# Search for the specific file content
cat src/main/webapp/app/shared/monaco-editor/model/actions/emoji.action.ts

# Search for class implementation and subscription handling
rg -l "class EmojiAction" --type ts

Length of output: 4838


Script:

#!/bin/bash
# Check if TextEditorAction implements OnDestroy
cat src/main/webapp/app/shared/monaco-editor/model/actions/text-editor-action.model.ts

# Check if subscriptions are managed at a higher level
rg -A 5 "extends TextEditorAction" --type ts

Length of output: 31120

src/test/javascript/spec/component/shared/metis/postings-markdown-editor/postings-markdown-editor.component.spec.ts (1)

11-11: Import statement is appropriate.

The import of Subject from 'rxjs' is necessary for handling observables in the test cases.

HawKhiem
HawKhiem previously approved these changes Oct 25, 2024
Copy link

@HawKhiem HawKhiem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested on TS1. Everything works as described. One thing I would suggest: Could you make it so that after picking the emoji, the emoji picker doesn't close down and one can keep picking more emojis. Thank you!

Communication._.Practical.Course_.Interactive.Learning.WS24_25.-.Google.Chrome.2024-10-25.20-22-37.mp4

Copy link

@kevinfischer4 kevinfischer4 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested on TS3. Feature works as expected. Tested in general, direct message and group chats. Would be good if it would be possible to use multiple emojis without opening the menu again.

@asliayk
Copy link
Contributor Author

asliayk commented Oct 27, 2024

It has been decided that the emoji panel should close after an emoji is selected (as in Slack). I would appreciate it if you could review it again with this in mind. :)

Copy link

@HawKhiem HawKhiem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested on TS2. Reapprove!

image

Copy link

@Cathy0123456789 Cathy0123456789 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested on TS2. Works great, thank you!
image

Something I noticed is you cannot send these smileys :) at all anymore then? It automatically converts them with no way to change them back?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
client Pull requests that update TypeScript code. (Added Automatically!) component:Communication ready for review tests
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.